﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Research.Kinect.Nui;
using System.Threading;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Runtime.InteropServices;
using System.Drawing;

namespace MocKinect.Proxies
{
    [Serializable]
    public class SerialisablePlanarImage
    {
        public int Width;
        public int Height;
        public int BytesPerPixel;
        //[NonSerialized]
        public byte[] Bits;

        public static explicit operator SerialisablePlanarImage(PlanarImage planarImage)
        {
            SerialisablePlanarImage serialisablePlanarImage = new SerialisablePlanarImage();
            serialisablePlanarImage.SetFromPlanarImage(planarImage);
            return serialisablePlanarImage;
        }

        public static explicit operator PlanarImage(SerialisablePlanarImage serialisablePlanarImage)
        {
            PlanarImage planarImage = new PlanarImage()
            {
                Width = serialisablePlanarImage.Width,
                Height = serialisablePlanarImage.Height,
                BytesPerPixel = serialisablePlanarImage.BytesPerPixel,
            };
            planarImage.Bits = new byte[serialisablePlanarImage.Bits.Length];
            Array.Copy(serialisablePlanarImage.Bits, planarImage.Bits, planarImage.Bits.Length);
            return planarImage;
        }

        public void SerializeImage(string RecordFilename, SerialisableImageFrame frame)
        {
            GCHandle arrayHandle = GCHandle.Alloc(frame.Image.Bits, GCHandleType.Pinned);
            Bitmap bmp = new Bitmap(this.Width, this.Height,
                this.Width * frame.Image.BytesPerPixel,
                frame.Image.BytesPerPixel == 2 ? System.Drawing.Imaging.PixelFormat.Format16bppRgb555 : System.Drawing.Imaging.PixelFormat.Format32bppRgb,
                arrayHandle.AddrOfPinnedObject());
            System.Threading.Thread ts = new System.Threading.Thread
              (delegate()
              {
                  bmp.Save(RecordFilename + frame.FrameNumber.ToString("0000") + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
                  bmp.Dispose();
                  arrayHandle.Free();
              });
            ts.Start();
        }

        public void SetFromPlanarImage(PlanarImage planarImage)
        {
            Width = planarImage.Width;
            Height = planarImage.Height;
            BytesPerPixel = planarImage.BytesPerPixel;
            if (Bits == null || Bits.Length != planarImage.Bits.Length)
            {
                Bits = new byte[planarImage.Bits.Length];
            }
            Array.Copy(planarImage.Bits, Bits, Bits.Length);
        }
    }

    [Serializable]
    public class SerialisableImageFrame
    {
        public long Timestamp;
        public int FrameNumber;
        public ImageType Type;
        public ImageResolution Resolution;
        public SerialisablePlanarImage Image;
        [NonSerialized]
        private bool _isNew = false;

        public SerialisableImageFrame()
        {
            Image = new SerialisablePlanarImage();
        }

        public static explicit operator SerialisableImageFrame(ImageFrame imageFrame)
        {
            SerialisableImageFrame serialisableImageFrame = new SerialisableImageFrame();
            serialisableImageFrame.SetFromImageFrame(imageFrame);
            return serialisableImageFrame;
        }

        public static explicit operator ImageFrame(SerialisableImageFrame serialisableImageFrame)
        {
            ImageFrame imageFrame = new ImageFrame()
            {
                FrameNumber = serialisableImageFrame.FrameNumber,
                Resolution = serialisableImageFrame.Resolution,
                Image = (PlanarImage)serialisableImageFrame.Image,
                Timestamp = serialisableImageFrame.Timestamp,
                Type = serialisableImageFrame.Type,
            };
            return imageFrame;
        }

        public void SetFromImageFrame(ImageFrame imageFrame)
        {
            FrameNumber = imageFrame.FrameNumber;
            Resolution = imageFrame.Resolution;
            Image.SetFromPlanarImage(imageFrame.Image);
            Timestamp = imageFrame.Timestamp;
            Type = imageFrame.Type;
            _isNew = true;
        }

        public void SerializeImage(string recordFilename)
        {
            Image.SerializeImage(recordFilename, this);
        }

        public void SerializeFrameOnly(BinaryFormatter binaryFormatter, FileStream fileStream)
        {
            binaryFormatter.Serialize(fileStream, this);
            _isNew = false;
        }

        public void Serialize(BinaryFormatter binaryFormatter, FileStream fileStream, string recordFilename)
        {
            if (_isNew)
                SerializeFrameOnly(binaryFormatter, fileStream);
            //SerializeImage(recordFilename);
        }
    }
}
